<?php

namespace App\Services\Eto;


use App\Services\Array2XML;
use App\Services\Eto\EtoClientException;
use Log;
class EtoClientNew
{

    /**
     * 单个推单URL
     * @var string
     */
    // protected $singlePushUrl = 'http://vip.hnsto.cn:88/hnsto/servlet/EPortBillinfoInterfaceRSA';
    protected $singlePushUrl = 'http://interface.hnsto.cn:88/hnsto/servlet/RequestStoBillNumberVip';

    /**
     * 批量推单URL
     * @var string
     */
    // protected $batchPushUrl = 'http://interface.hnsto.cn:88/hnsto/servlet/eTradeBillinfoInterface';
    protected $batchPushUrl = 'http://interface.hnsto.cn:88/hnsto/servlet/RequestStoBillNumberVip';

    /**
     * 热敏号段
     * @var string
     */
//    protected $billUrl = 'http://vip.hnsto.cn:88/hnsto/servlet/RequestStoBillNumberVip';

    protected $billUrl = 'http://vip.hnsto.cn:88/hnsto/servlet/eTradeBillinfoInterfaceUn';
    /**
     * 商户号:从申通处获取的商户号
     * @var string
     */
    protected $scid = '90000';
    /**
     * 公钥
     * @var string
     */
    protected $pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu7jiT96WeZoQ5abi1jGzmeMtypS8Pnbxc16whLeO23cUmgoan4hWjszl/f837bsajaj0iCoFLM3jEYdigq67UK7w+MmSXUiZToOEUzWkZAemX3zUQC4b0g8pOGwd6mXGoraXCfvxIbSIu+Tbxa0saZk0kksXvi1S2A0W3VQlcuwIDAQAB";

    /**
     * 电商平台海关备案号码
     * @var
     */
    protected $ecpCode = '';

    /**
     * 电商平台备案名称
     * @var
     */
    protected $ecpName = '';

    /**
     * 加密key
     * @var
     */
    protected $key;

    /**
     * @var
     */
    protected $logisticsCodeCiq;


    protected $logisticsCodeCus;


    protected $name;


    public function __construct()
    {

        $einfo = config('eorderinfo');


        $config = config('shipping.eto.config');
        $this->singlePushUrl = $config['singlePushUrl_new'];
        $this->batchPushUrl = $config['batchPushUrl'];
        $this->billUrl = $config['billUrl'];
        $this->scid = $config['StoCustomerID'];
        $this->pubkey = $config['publicKey'];
        $this->key = $config['key'];
        $this->logisticsCodeCiq = $config['logisticsCodeCiq'];
        $this->logisticsCodeCus = $config['logisticsCodeCus_new'];
        $this->name = $config['name'];


        $this->ecpCode = $einfo['ecpCodeCus_new'];//电商平台代码
        $this->ecpName = $einfo['ecpNameCus'];//电商平台名称

        //$this->shipper = $einfo['shipper'];
        $this->shipper = '河南中原福塔电子商务有限公司';
        $this->shipperAddress = $einfo['shipperAddress'];
        $this->shipperTelephone = $einfo['shipperTelephone'];

        $this->ecpCodeCus_new = $einfo['ecpCodeCus_new'];
        $this->companyName = $einfo['companyName'];
        $this->phone = $einfo['phone'];
        $this->address = $einfo['address'];

    }

    public function getStoBillNumber($number = 100)
    {

        $data = [
            'checkData' => md5($this->scid . $number . '@Sto.2014'),//CheckData:MD5(客户编号+申请号码数+@Sto.2014),如例中的 0a14f5fcb9edc7e83a94bf27d6153d06 为 MD5("900005000@Sto.2014") 值
            'Rdate' => date('Y-m-d H:i:s', time()),
            'CustomerID' => $this->scid,
            'Key' => $this->key,
            'Rnumber' => $number
        ];
        Array2XML::init($version = '1.0', $encoding = 'GBK', $format_output = true);
        $xml = Array2XML::createXML('RequestInfo', $data);
        $xml = $xml->saveXML();
        $xml = iconv("UTF-8", "GBK", $xml);

        $this->makeRequest($this->billUrl, ['billnum_interface' => urlencode($xml)]);

    }


    public function pushSingle($order, $current_time)
    {

        //批次号
        // $batchNumbers = strtotime($order->add_time);
        $batchNumbers = strtotime($current_time);
        $nowHour = date('H',$batchNumbers);
        $batchNumbers = date('Ymd',$batchNumbers);
        if($nowHour>=0 && $nowHour<12){
            $batchNumbers .= '1';
        }elseif($nowHour>=12 && $nowHour<24){
            $batchNumbers .= '2';
        }

        $weight = 0;//重量
        $quantity = '';//商品总数量
        $net_weight = 0.00;     //净重
        // Array2XML::init($version = '1.0', $encoding = 'GBK', $format_output = true);
        Array2XML::init($version = '1.0', $encoding = 'utf-8', $format_output = true);

        //dd($order);
        foreach ($order->orderGoods as $k => $goods) {

            $buy_number = $goods->buy_number;
            $weight= $weight+$goods->weight*$buy_number;
            $quantity = $quantity+$buy_number;
            $net_weight +=$goods->buy_number*$goods->net_weight;
        }

        $row['row'][] = array(
            '@attributes' => array(
                'id' =>1
            ),
            // 'CheckData' => MD5($this->scid . $order->order_sn . '@Sto.2014'),//校验码
            'CheckData' => MD5($this->scid . '||' . $this->ecpCodeCus_new . '||' . $order->order_sn),//校验码,MD5(客户编号||电商代码||订单编号)
// 'declareDate' => date('Y-m-d', time()),//申报日期
            'StoCustomerID' => $this->scid,
            'ecpCode' => $this->ecpCode,//电商平台代码
// 'ecpName' => $this->ecpName,//电商平台名称
            'orderNo' => $order->order_sn,
            //'LogisticsNo'=>'',//(方案1默认不填)填写已绑定的申 通单号;未绑定则 为空(方案一), 由接口自动分配 运单号。限有发 放记录且未使用 的申通单号
            //'TrackingNo'=>'',
// 'shipper'=>$this->shipper,
// 'shipperAddress'=>$this->shipperAddress,
// 'shipperTelephone'=>$this->shipperTelephone,
// 'shipperCountryCiq' => 156,//发件人所在国(海)
'LogisticsNo' => '',
            'Consignor' => $this->companyName,            //发件人
            'TelephoneNum' => $this->phone,         //发件人电话
            'ConsignorAdd' => $this->address,         //发件地址
'shipperCountryCiq' => '156',          //非必填，发件人所在国(检), 按国检申报代码
'shipperCountryCus' => '142',          //必填，发件人所在国(海),按海关申报代码
            'consignee' => trim($order->consignee),//收件人
// 'idType' => $order->id_type,//证件类型
// 'customerId' => trim($order->id_card),//证件号码
            'consigneeTelephone' => trim($order->mobile),//收货人电话
            'Province' => trim($order->province),
            'City' => trim($order->city),
            'Zone' => trim($order->district),
            'consigneeAddress' => trim($order->province) . trim($order->city) . trim($order->district) . trim($order->address),//收件地址
            'consigneeCountryCiq' => '156',//收件人所在国(检)
            'consigneeCountryCus' => '142',//收件人所在国(海)
'idType' => $order->id_type,            //必填，收件人证件类型,1-身份证，只能 为1
'customerId' => $order->id_card,         //必填，收件人证件号码
// 'stockFlag' => $order->stockFlag,          //必填，集货/备货,1-集货,2-备货
'stockFlag' => '2',          //必填，集货/备货,1-集货,2-备货
'voyageNo' => '',           //航班班次号,集货模式必填
'totalLogisticsNo' => '',           //总单号,集货模式必填
            'weight' => number_format(trim($weight),2),//毛量(Kg)
            //'quantity'=>$goods->weight,//净重(Kg)
            //'packNum'=>'',//进出口标识
// 'quantity' => $quantity,//商品数量
'netWeight' => number_format(trim($net_weight),2),          //净重,两位小数Number(10, 2),>0
// 'packNo' => $quantity,             //件数,整数Number(9)，必须等于 1
'packNo' => 1,             //件数,整数Number(9)，必须等于 1
'CurrencyCus' => '142',        //币制(海), 海关币制代码，限 制人民币142
'CurrencyCiq' => '156',           //币制（检）.国检币制代码，限 制人民币156
            'ieType' => 'I',//进出口标识,I:进口,E-出口
// 'stockFlag' => '2',//集货/备货 1-集货,2-备货
// 'batchNumbers' => 'ZYFT'.$batchNumbers,
// 'billType' => '1',//暂定写 1-总运单
            //'note'=>'',//备注
//                'totalLogisticsNo' => $order->order_sn,//总单号
//                'goodsName' => $goods->goods_name,//货物品名
            //'destinationPort'=>'',
//                'packageTypeCus' => $goods->packageTypeCus,//包装类别代码(海)
// 'packageTypeCiq' => '4M',//包装类别代码(检)
// 'transportationMethod' => 8,//运输方式(检)//8:保税仓库
'freight' => '0',
'insuredFee' => '0',
            'shipCode' => '20',//运输方式代码 //20:船舶
// 'agentCode' => '4101983436',
// 'agentName' => '河南中启保税报关有限公司',
// 'tradeCountryCiq' => '156',

'codMoney' => '0.00',           //代收货款金额, Number(10, 2), 新增：代收货款必 须配合代收货款专 用面单或单号使用
'interFaceType' => '',          //接口类型,特定用途。一般为 空
'modifyFlag' => '1',         //修改标识, 报文类型：1新增,2 修改,3删除。为空 即默认1
'appStatus' => '2',          //申报状态, 申报状态：1暂存,2 申报。为空即默认2
'note' => '',           //备注
'goodsInfo' => '',
'goodsItem' => '',          //货物清单

//                'shipCodeInsp' => $goods->tradeCountryCus,//运输工具代码(检)
//                'tradeCountry' => $goods->tradeCountryCiq,//贸易国别
//                'jcbOrderTime' => $goods->tradeCountryCiq,//进/出境日期
//                'jcbOrderPort' => 'ZHENGZHOU',//进/出境口岸
//                'transferType' => $goods->shipCode,//运输方式代码
//                'jcbOrderPortInsp' => '',//进/出境口岸(检)
//                'shipName' => '',//运输工具名称(关)
//                'shipNameInsp' => '',//运输工具名称(检)
//                'applyPortInsp' => '',//检疫申报口岸
//                'transferRegionInsp' => '',//检疫起运/抵运国 代码
//                'cbeCodeInsp' => '',//电商企业国检备案 编号
//                'coinInsp' => '',//币制代码
//                'cbeCode' => '',//电商企业代码
            //'cbeName'=>'',
//                'declarePort' => '',//海关申报口岸代码
            //'modifyMark'=>'',
//                'stockFlag' => '',//新增字段 1 集货,2 备货
//            'goodsItem'=>[
//                0=>[
//                    '@attributes' => array(
//                        'id' => 1
//                    ),
//                    'itemNo'=>'',
//                    'itemName'=>'',
//                    'itemModel'=>'',
//                    'itemQuantity'=>'',
//                    'itemDescribe'=>'',
//                ]
//            ]
        );






        $xmlObj = Array2XML::createXML('rows', $row);

        $xml = $xmlObj->saveXML();
// echo $xml;exit('stop');

        // Log::info('申通请求xml:'.mb_convert_encoding($xml,'UTF-8','GBK'));
        Log::info('申通请求xml:'.$xml);
        $encode = mb_detect_encoding($xml, array('ASCII','UTF-8','GB2312','GBK','BIG5')); 
        Log::info('申通请求xml编码格式:'.$encode);

        Log::info('申通请求url:'.$this->singlePushUrl);

        return $this->makeRsaRequest($this->singlePushUrl, $xml);


    }




    public function makeRsaRequest($url, $xml)
    {

        //生成证书
        $pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($this->pubkey, 64, "\n") . "-----END PUBLIC KEY-----\n";
        //算出公钥
        $key = openssl_pkey_get_public($pem);
        //公钥加密原始字符串
        $rsad = $this->publicEncrypt($xml, $key);

        if (!empty($rsad)) {
            //构造post参数数组，数组索引为特定的字符串请勿更改
            /*$postArray = array(
                "billinfo_interface" => $rsad,
                "data_digest" => urlencode(base64_encode(md5($xml))),
                "key" => $this->key
            );*/
            $postArray = array(
                'version' => '4.0',
                'encrypt_type' => 'RSA',           //RSA或为空、UN, 忽略大小写，为空时即默认 使用RSA加密方式；UN为 不加密方式。
                "billinfo_interface" => $rsad,      //即运单xml数据加密或 编码之后的字符串
                "data_digest" => urlencode(base64_encode(md5($xml))),           //摘要，xml原始内容的 校验
                "key" => $this->key  //授权码,申通系统分配
            );
            //post数据到指定地址
            return $this->makeRequest($url, $postArray);


        }
    }

    /**
     * 公钥加密函数，分段加密原始xml
     *
     * @param String $data
     * @param Source publickey source id $key
     * @return String加密之后先base64再urlencode的字串
     */
    function publicEncrypt($data, $key)
    {
        if (empty($data) || empty($key)) {
            return null;
        }
        $resultb = "";
        $dataArray = str_split($data, 117);
        foreach ($dataArray as $d) {
            if (openssl_public_encrypt($d, $result, $key)) {
                $resultb .= $result;
            } else return null;
        }
        return urlencode(base64_encode($resultb));
    }

    /**
     * 构建请求
     * @param $data
     * @return mixed|string
     */
    private function makeRequest($url, $data)
    {

        try {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));


            $response = curl_exec($ch);
// Log::info('请求中的参数：'.http_build_query($data));
// echo $response; exit();

        }catch (\Exception $e){

            throw new EtoClientException($e->getMessage());
        }

        $repsonXmlObj = simplexml_load_string($response);

        foreach ($repsonXmlObj->Result as $rrs){
            $logisticsNO=$rrs->logisticsNo;
            if($rrs->Status=='Success'){
                return $logisticsNO;
            }
            else{
                throw new EtoClientException($rrs->Remark);
            }
        }

    }


}